﻿using System;
using System.IO;
using System.Text;

namespace WpfAdmin.Everything {
    internal class SearchResult : ISearchResult {
        private readonly uint replyId;
        private readonly uint index;
        public SearchResult(int index, uint replyId) {
            this.index = (uint)index;
            this.replyId = replyId;
        }

        public long Index => index;

        public bool IsFile => EverythingWrapper.Everything_IsFileResult(index);
        public bool IsFolder => EverythingWrapper.Everything_IsFolderResult(index);
        public bool IsVolume => EverythingWrapper.Everything_IsVolumeResult(index);

        private string fullPath;
        public string FullPath {
            get {
                if (fullPath == null) {
                    var builder = new StringBuilder(32767);
                    EverythingWrapper.Everything_SetReplyID(replyId);
                    EverythingWrapper.Everything_GetResultFullPathName(index, builder, 32767);
                    fullPath = builder.ToString();
                }
                return fullPath;
            }
        }

        public string Path {
            get {
                try {
                    return !string.IsNullOrEmpty(FullPath)
                        ? System.IO.Path.GetDirectoryName(FullPath)
                        : string.Empty;
                } catch (Exception ex) {
                    LastException = ex;
                    return FullPath;
                }
            }
        }

        public string FileName {
            get {
                try {
                    return !string.IsNullOrEmpty(FullPath)
                        ? System.IO.Path.GetFileName(FullPath)
                        : string.Empty;
                } catch (Exception ex) {
                    LastException = ex;
                    return FullPath;
                }
            }
        }

        public long Size {
            get {
                EverythingWrapper.Everything_SetReplyID(replyId);
                if (EverythingWrapper.Everything_GetResultSize(index, out long size)) {
                    return size;
                } else {
                    LastException = new InvalidOperationException("Failed to get file size.");
                    return -1; // Indicating an error
                }
            }
        }

        public uint RunCount {
            get {
                EverythingWrapper.Everything_SetReplyID(replyId);
                return EverythingWrapper.Everything_GetResultRunCount(index);
            }
        }

        public uint Attributes {
            get {
                EverythingWrapper.Everything_SetReplyID(replyId);
                uint attributes = EverythingWrapper.Everything_GetResultAttributes(index);
                if (attributes > 0) {
                    return attributes;
                }
                if (!string.IsNullOrEmpty(FullPath)) {
                    try {
                        return (uint)File.GetAttributes(FullPath);
                    } catch (Exception ex) {
                        LastException = ex;
                        return 0;
                    }
                }
                return 0;
            }
        }

        private delegate bool MyDelegate(uint index, out long date);

        public DateTime Created => GenericDate(EverythingWrapper.Everything_GetResultDateCreated, File.GetCreationTime);

        public DateTime Modified => GenericDate(EverythingWrapper.Everything_GetResultDateModified, File.GetLastWriteTime);

        public DateTime Accessed => GenericDate(EverythingWrapper.Everything_GetResultDateAccessed, File.GetLastAccessTime);

        public DateTime Executed => GenericDate(EverythingWrapper.Everything_GetResultDateRun, File.GetLastAccessTime);

        public DateTime RecentlyChanged => GenericDate(EverythingWrapper.Everything_GetResultDateRecentlyChanged, File.GetLastWriteTime);

        public DateTime Run => GenericDate(EverythingWrapper.Everything_GetResultDateRun, File.GetLastAccessTime);

        public Exception LastException { get; private set; }

        private DateTime GenericDate(MyDelegate func, Func<string, DateTime> fallbackDelegate) {
            EverythingWrapper.Everything_SetReplyID(replyId);
            if (func(index, out long date) && date >= 0) {
                return DateTime.FromFileTime(date);
            }
            return !string.IsNullOrEmpty(FullPath)
                ? fallbackDelegate(FullPath)
                : DateTime.MinValue;
        }
    }
}
